package com.mo.tools.stream;

import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * @author: e-Xingfu.Yang
 * @description:
 * @date:created in 2022/1/13 18:12
 * @modificed by:
 */
public class Predicates {
    /**
     * 根据对象字段去重
     * eg: list.stream().filter(distinct(Order::id))
     *
     * @param function
     * @param <T>
     * @return
     */
    public static <T> Predicate<T> distinct(Function<T, ?> function) {
        Map<Object, Boolean> map = new ConcurrentHashMap<>(16);
        return key -> map.putIfAbsent(function.apply(key), Boolean.TRUE) == null;
    }

    /**
     * 根据对象空值过滤
     *
     * @param function
     * @param <T>
     * @return
     */
    public static <T> Predicate<T> empty(Function<T, ?> function) {
        return item -> ObjectUtils.isEmpty(function.apply(item));
    }

    /**
     * 根据对象字段非空过滤
     *
     * @param function
     * @param <T>
     * @return
     */
    public static <T> Predicate<T> notEmpty(Function<T, ?> function) {
        return item -> !ObjectUtils.isEmpty(function.apply(item));
    }

    /**
     * 两个collection的交集
     * collection过滤另一个collection存在的数据
     *
     * @param list
     * @param function
     * @param <T>
     * @return
     */
    public static <T> Predicate<T> existsByList(Function<T, ?> function, Collection<T> list) {
        Collection<?> finalList = Optional.ofNullable(list).orElseGet(ArrayList::new);
        return item -> finalList.contains(function.apply(item));
    }

    /**
     * 前一个collection是后一个collection的补集
     * collection过滤另一个collection不存在的数据
     *
     * @param list
     * @param function
     * @param <T>
     * @return
     */
    public static <T> Predicate<T> notExistsByList(Function<T, ?> function, Collection<T> list) {
        Collection<?> finalList = Optional.ofNullable(list).orElseGet(ArrayList::new);
        return item -> !finalList.contains(function.apply(item));
    }

}
